package com.xh.bussiness.thirdapi.xuebang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.xh.bussiness.permission.bean.request.RoleRequest;
import com.xh.bussiness.permission.bean.request.UserRequest;
import com.xh.bussiness.permission.model.Role;
import com.xh.bussiness.permission.model.School;
import com.xh.bussiness.permission.model.User;
import com.xh.bussiness.permission.service.IRoleService;
import com.xh.bussiness.permission.service.IUserService;
import com.xh.bussiness.system.bean.dto.StudentBean;
import com.xh.bussiness.system.model.Student;
import com.xh.bussiness.system.service.ISchoolService;
import com.xh.bussiness.system.service.IStudentService;
import com.xh.bussiness.thirdapi.xuebang.config.XuebangConfig;
import com.xh.bussiness.thirdapi.xuebang.constant.XuebangClassStatusEnum;
import com.xh.bussiness.thirdapi.xuebang.constant.XuebangConstant;
import com.xh.bussiness.thirdapi.xuebang.dto.VO.XuebangPageVO;
import com.xh.bussiness.thirdapi.xuebang.dto.VO.XuebangResultVO;
import com.xh.bussiness.thirdapi.xuebang.dto.request.*;
import com.xh.bussiness.thirdapi.xuebang.model.*;
import com.xh.bussiness.thirdapi.xuebang.service.IXuebangService;
import com.xh.bussiness.tms.model.Class;
import com.xh.bussiness.tms.model.ClassStudent;
import com.xh.bussiness.tms.service.IClassManageService;
import com.xh.bussiness.tms.service.IClassStudentService;
import com.xh.core.util.CacheUtils;
import com.xh.core.util.DateUtils;
import com.xh.core.util.StringUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Pitt Cheung
 * @date 2021/7/5 17:27
 */
@Service
public class XuebangServiceImpl implements IXuebangService {

    @Autowired
    private XuebangConfig config;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private IRoleService roleService;
    @Autowired
    private ISchoolService schoolService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IStudentService studentService;
    @Autowired
    private IClassManageService classManageService;
    @Autowired
    private IClassStudentService classStudentService;

    private String getToken() {
        try {
            Object o = CacheUtils.get(XuebangConstant.CACHE_KEY);
            if (o == null) {
                HttpHeaders headers = new HttpHeaders();
                headers.add("X-XB-CLIENT-PASS", config.getXbClientPass());
                ResponseEntity<JSONObject> exchange = restTemplate.exchange(
                        config.getHost() + XuebangConstant.URL_GET_TOKEN,
                        HttpMethod.GET, new HttpEntity<String>(headers),
                        JSONObject.class,
                        config.getClientId());

                JSONObject body = exchange.getBody();
                if (body != null) {
                    String token = body.get("token") == null ? null : body.get("token").toString();
                    CacheUtils.set(XuebangConstant.CACHE_KEY, token, 5000);
                    return token;
                }
            } else {
                return CacheUtils.get(XuebangConstant.CACHE_KEY).toString();
            }
        } catch (RestClientException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void initRole() {
        Map<String, Object> params = new HashMap<>();
        params.put("pageNo", 0);
        params.put("pageSize", 100);

        JSONObject jsonObject = sendGetRequest(XuebangConstant.URL_GET_ROLE, params);
        if (jsonObject != null) {
            XuebangResultVO result = JSONUtil.toBean(jsonObject, XuebangResultVO.class);
            if (result.getData() != null && !CollectionUtil.isEmpty(result.getData().getDatas())) {
                for (Object data : result.getData().getDatas()) {
                    XuebangRole xuebangRole = BeanUtil.toBean(data, XuebangRole.class);

                    Role role = roleService.queryByThirdId(xuebangRole.getId().toString());
                    if (role == null) {
                        RoleRequest roleRequest = new RoleRequest();
                        roleRequest.setId(xuebangRole.getId().toString());
                        roleRequest.setName(xuebangRole.getName());
                        roleRequest.setIsSystem(1);

                        roleService.addRole(roleRequest);
                    } else {
                        role.setName(xuebangRole.getName());
                        roleService.update(role);
                    }
                }
            }
        }
    }

    @Override
    public void syncOrganization() {
        boolean hasRecord = true;
        Integer pageNo = 0;
        Integer pageSize = 100;
        QueryXuebangOrgRequest request = new QueryXuebangOrgRequest();
        request.setPageSize(pageSize);
        while (hasRecord) {
            request.setPageNo(pageNo);
            XuebangResultVO resultVO = queryXuebangOrg(request);
            if (resultVO != null && resultVO.getData() != null) {
                XuebangPageVO data = resultVO.getData();
                List<Object> datas = data.getDatas();
                if (data.getRowCount() > 0 && CollectionUtil.isNotEmpty(datas)) {
                    for (Object o : datas) {
                        XuebangOrganization xuebangOrganization = BeanUtil.toBean(o, XuebangOrganization.class);
                        School school = schoolService.querySchoolByThirdId(xuebangOrganization.getId().toString());
                        if (school == null) {
                            school = School.builder()
                                    .thirdId(xuebangOrganization.getId().toString())
                                    .schoolName(xuebangOrganization.getName())
                                    .provinceId(xuebangOrganization.getProvinceId())
                                    .provinceName(xuebangOrganization.getProvinceName())
                                    .cityId(xuebangOrganization.getRegion())
                                    .cityName(xuebangOrganization.getRegionName())
                                    .schoolMobile(xuebangOrganization.getContact())
                                    .schoolAddress(xuebangOrganization.getAddress())
                                    .build();
                            schoolService.saveOrUpdate(school);
                        }
                    }
                    pageNo++;
                } else {
                    hasRecord = false;
                }
            }else{
                hasRecord = false;
            }
        }
    }

    @Override
    public XuebangResultVO queryXuebangOrg(QueryXuebangOrgRequest request) {
        Map<String, Object> params = BeanUtil.beanToMap(request);
        JSONObject result = sendGetRequest(XuebangConstant.URL_GET_ORG, params);
        return JSONUtil.toBean(result, XuebangResultVO.class);
    }

    @Override
    public void syncUser() {
        boolean hasRecord = true;
        Integer pageNo = 0;
        Integer pageSize = 100;
        QueryXuebangUserRequest request = new QueryXuebangUserRequest();
        request.setPageSize(pageSize);
        request.setEnableFlg(0);

        List<Role> roles = roleService.queryAll();
        List<School> schools = schoolService.queryAll();
        while (hasRecord) {
            request.setPageNo(pageNo);
            XuebangResultVO resultVO = queryXuebangUser(request);
            if (resultVO != null && resultVO.getData() != null) {
                Long rowCount = resultVO.getData().getRowCount();
                List<Object> datas = resultVO.getData().getDatas();
                if (rowCount > 0 && CollectionUtil.isNotEmpty(datas)) {
                    for (Object data : datas) {
                        XuebangUser xuebangUser = BeanUtil.toBean(data, XuebangUser.class);
                        if (xuebangUser.getHasDimission().equals(1)) {
                            User exists = userService.queryUserByThirdId(xuebangUser.getUserId().toString(), 4);
                            userService.deleteUser(exists.getId());
                            continue;
                        }
                        User exists = userService.queryUserByThirdId(xuebangUser.getUserId().toString(), 4);
                        if (exists != null) {
                            User user = new User();
                            user.setId(exists.getId());
                            user.setStatus(0);
                            user.setUsername(xuebangUser.getName());
                            user.setNickname(xuebangUser.getName());
                            user.setMobile(xuebangUser.getContact());
                            userService.update(user);
                        } else {
                            List<String> userRoleIds = null;
                            if (StringUtils.isNotEmpty(xuebangUser.getRoleNames())) {
                                List<String> roleNames = Arrays.asList(xuebangUser.getRoleNames().split(","));
                                userRoleIds = roles.stream().filter(item -> roleNames.contains(item.getName())).map(Role::getId).collect(Collectors.toList());
                            }
                            List<Object> userManageOrganizations = xuebangUser.getUserManageOrganizations();
                            List<String> userSchoolNames = new ArrayList<>();
                            if (CollectionUtil.isNotEmpty(userManageOrganizations)) {
                                for (Object userManageOrganization : userManageOrganizations) {
                                    JSONObject jsonObject = BeanUtil.toBean(userManageOrganization, JSONObject.class);
                                    userSchoolNames.add(jsonObject.get("organizationName").toString());
                                }
                            }
                            List<String> userSchoolIds = schools.stream().filter(item -> userSchoolNames.contains(item.getSchoolName())).map(School::getId).collect(Collectors.toList());

                            UserRequest userRequest = UserRequest.builder()
                                    .id(xuebangUser.getUserId().toString())
                                    .mobile(xuebangUser.getContact())
                                    .nickname(xuebangUser.getName())
                                    .username(xuebangUser.getName())
                                    .status(0)
                                    .isFront(1)
                                    .isAdmin(1)
                                    .source(4)
                                    .thirdId(xuebangUser.getUserId().toString())
                                    .roleIds(userRoleIds)
                                    .schoolIds(userSchoolIds)
                                    .build();
                            userService.addUser(userRequest);
                        }
                    }
                    pageNo++;
                } else {
                    hasRecord = false;
                }
            } else {
                hasRecord = false;
            }
        }

    }

    @Override
    public XuebangResultVO queryXuebangUser(QueryXuebangUserRequest request) {
        Map<String, Object> params = BeanUtil.beanToMap(request);
        JSONObject result = sendGetRequest(XuebangConstant.URL_GET_USER, params);
        return JSONUtil.toBean(result, XuebangResultVO.class);
    }

    @Override
    public XuebangResultVO queryXuebangStudent(QueryXuebangStudentRequest request) {
        Map<String, Object> params = BeanUtil.beanToMap(request);
        JSONObject result = sendGetRequest(XuebangConstant.URL_GET_STUDENT, params);
        return JSONUtil.toBean(result, XuebangResultVO.class);
    }

    @Override
    public void syncStudent() {
        QueryXuebangStudentRequest request = new QueryXuebangStudentRequest();
        request.setStuStatus(1);
        request.setPageSize(100);
        request.setStudentContractType("OFFICIAL_STUDENT");

        Integer pageNo = 0;
        boolean hasRecord = true;
        while (hasRecord) {
            request.setPageNo(pageNo);
            XuebangResultVO resultVO = queryXuebangStudent(request);
            if (resultVO != null && resultVO.getData() != null) {
                Long rowCount = resultVO.getData().getRowCount();
                List<Object> datas = resultVO.getData().getDatas();
                if (rowCount > 0 && CollectionUtil.isNotEmpty(datas)) {
                    for (Object data : datas) {
                        XuebangStudent xuebangStudent = BeanUtil.toBean(data, XuebangStudent.class);
                        if (xuebangStudent != null) {
                            Student existsStudent = studentService.queryStudentByThridId(xuebangStudent.getStudentId().toString());
                            if (existsStudent == null) {
                                StudentBean studentBean = new StudentBean();
                                studentBean.setLwSchoolId(xuebangStudent.getBlCampusId() == null ? "" : xuebangStudent.getBlCampusId().toString());
                                studentBean.setSchoolName(xuebangStudent.getBlCampusName());
                                studentBean.setThirdId(xuebangStudent.getStudentId().toString());
                                studentBean.setName(xuebangStudent.getName());
                                studentBean.setMotherPhone(xuebangStudent.getContact());
                                studentBean.setFatherPhone(xuebangStudent.getFatherPhone());
                                studentBean.setGradeId(xuebangStudent.getGradeId().toString());
                                studentBean.setGradeName(xuebangStudent.getGradeName());
                                studentBean.setSex(xuebangStudent.getSex());
                                studentBean.setHead(xuebangStudent.getHeaderFaceImageUrl());
                                studentBean.setSource(4);
                                studentService.addStudent(studentBean);
                            }
                        }
                    }
                    pageNo++;
                } else {
                    hasRecord = false;
                }
            } else {
                hasRecord = false;
            }
        }
    }


    @Override
    public XuebangResultVO queryXuebangClass(QueryXuebangClassRequest request) {
        Map<String, Object> params = BeanUtil.beanToMap(request);
        JSONObject result = sendGetRequest(XuebangConstant.URL_GET_CLASS, params);
        return JSONUtil.toBean(result, XuebangResultVO.class);
    }

    @Override
    public void syncXuebangClass() {
        QueryXuebangClassRequest request = new QueryXuebangClassRequest();
        //开班时间前推三个月
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MONTH, -3);
        request.setStartDateBegin(DateUtils.format(calendar.getTime(), "yyyy-MM-dd"));
        //开班时间后推6个月数据
        calendar.add(Calendar.MONTH, 9);
        request.setStartDateEnd(DateUtils.format(calendar.getTime(), "yyyy-MM-dd"));
        request.setPageSize(100);
        Integer pageNo = 0;
        boolean hasRecord = true;
        while (hasRecord) {
            request.setPageNo(pageNo);
            XuebangResultVO resultVO = queryXuebangClass(request);
            if (resultVO != null && resultVO.getData() != null) {
                List<Object> datas = resultVO.getData().getDatas();
                Long rowCount = resultVO.getData().getRowCount();
                if (rowCount > 0 && CollectionUtil.isNotEmpty(datas)) {
                    for (Object data : datas) {
                        XuebangClass xuebangClass = BeanUtil.toBean(data, XuebangClass.class);
                        if (xuebangClass != null && !xuebangClass.getStatus().equals("INVALID") && !xuebangClass.getStatus().equals("CONPELETE")) {
                            Class aClass = classManageService.queryClassByThridId(xuebangClass.getMiniClassId().toString(), "学邦TMS");
                            if (aClass == null) {
                                aClass = Class.builder()
                                        .orgId(xuebangClass.getBlCampusId() == null ? null : xuebangClass.getBlCampusId().toString())
                                        .gradeId(xuebangClass.getGradeId() == null ? null : xuebangClass.getGradeId().toString())
                                        .gradeName(xuebangClass.getGradeName())
                                        .subjectId(xuebangClass.getSubjectId() == null ? null : xuebangClass.getSubjectId().toString())
                                        .subjectName(xuebangClass.getSubjectName())
                                        .title(xuebangClass.getName())
                                        .status(XuebangClassStatusEnum.getVal(xuebangClass.getStatus()))
                                        .teacherId(xuebangClass.getTeacherId() == null ? null : xuebangClass.getTeacherId().toString())
                                        .teacherName(xuebangClass.getTeacherName())
                                        .assistantId(xuebangClass.getAssistantId() == null ? null : xuebangClass.getAssistantId().toString())
                                        .assistantName(xuebangClass.getAssistantName())
                                        .thirdId(xuebangClass.getMiniClassId() == null ? null : xuebangClass.getMiniClassId().toString())
                                        .source("学邦TMS")
                                        .startDate(StringUtils.isEmpty(xuebangClass.getStartDate()) ? null : DateUtils.date2LocalDate(DateUtils.parseDate(xuebangClass.getStartDate(), "yyyy-MM-dd")))
                                        .build();

                                aClass.setId(xuebangClass.getMiniClassId().toString());
                                classManageService.insert(aClass);

                                syncClassStudentByClassId(aClass);
                            }
                        }
                    }
                    pageNo++;
                } else {
                    hasRecord = false;
                }
            } else {
                hasRecord = false;
            }
        }
    }

    private void syncClassStudentByClassId(Class aClass) {
        Integer pageNo = 0;
        boolean hasRecord = true;
        Map<String, Object> params = new HashMap<>();
        params.put("pageSize", 100);
        params.put("miniClassId", aClass.getThirdId());

        while (hasRecord) {
            params.put("pageNo", pageNo);
            JSONObject jsonObject = sendGetRequest(XuebangConstant.URL_GET_CLASS_STUDENT, params);
            if (jsonObject != null) {
                XuebangResultVO resultVO = JSONUtil.toBean(jsonObject, XuebangResultVO.class);
                if (resultVO != null && resultVO.getData() != null) {
                    XuebangPageVO data = resultVO.getData();
                    Long rowCount = data.getRowCount();
                    List<Object> datas = data.getDatas();

                    if (rowCount > 0 && CollectionUtil.isNotEmpty(datas)) {
                        for (Object o : datas) {
                            XuebangClassStudent xuebangClassStudent = BeanUtil.toBean(o, XuebangClassStudent.class);
                            if (xuebangClassStudent != null) {
                                ClassStudent classStudent = new ClassStudent();
                                classStudent.setClassId(xuebangClassStudent.getMiniClassId() == null ? null : xuebangClassStudent.getMiniClassId().toString());
                                classStudent.setStudentId(xuebangClassStudent.getStudentId() == null ? null : xuebangClassStudent.getStudentId().toString());
                                classStudentService.insert(classStudent);
                            }
                        }
                        pageNo++;
                    }else{
                        hasRecord = false;
                    }
                }else{
                    hasRecord = false;
                }
            }else {
                hasRecord = false;
            }
        }

    }

    @Override
    public XuebangResultVO queryXuebangClassLesson(QueryXuebnagClassLessonRequest request) {
        Map<String, Object> params = BeanUtil.beanToMap(request);
        JSONObject result = sendGetRequest(XuebangConstant.URL_GET_CLASS_LESSON, params);
        if (result != null) {
            XuebangResultVO resultVO = JSONUtil.toBean(result, XuebangResultVO.class);
            return resultVO;
        }
        return null;
    }

    private JSONObject sendGetRequest(String url, Map<String, Object> params) {
        String urlParams = "";
        int len = params.size();
        if (MapUtils.isNotEmpty(params)) {
            urlParams += "?";
            for (String key : params.keySet()) {
                len --;
                if (params.get(key) != null) {
                    if (len > 0) {
                        urlParams += key + "=" + params.get(key)+"&";
                    }else{
                        urlParams += key + "=" + params.get(key);
                    }
                }
            }
        }
        if (StringUtils.isNotEmpty(urlParams)) {
            url += urlParams;
        }
        try {
            String token = getToken();
            HttpHeaders headers = new HttpHeaders();
            headers.add("X-XB-JWT", token);
            ResponseEntity<JSONObject> exchange = restTemplate.exchange(
                    config.getHost() + url,
                    HttpMethod.GET,
                    new HttpEntity<JSONObject>(headers),
                    JSONObject.class,
                    "params=1"
            );
            return exchange.getBody();
        } catch (RestClientException e) {
            e.printStackTrace();
        }
        return null;
    }
}
